package Worker;
import Commons.Address;
import Commons.Indirizzi;
import Commons.Logging.LogStatoCoda;
import Commons.Logging.Logger;
import Commons.Logging.LoggerContenutoCode;
import Commons.TaskDescriptor;
import Commons.Utility;
import Manager.TQueue;
import java.io.IOException;
import java.util.ArrayList;
import java.util.logging.Level;
import javax.xml.stream.XMLStreamException;


/**Questa classe descrive il TQueueManager.
 *
 * @author Team5
 */
public class TQueueManager implements TQueue,Runnable {

    //Attributes
    private Address addr;
    private ArrayList<TaskDescriptor> tQueue;
    private int portaDelWorker;
    Utility u2;
    Utility u3;
    /**
     * Oggetto per la gestione del logging dello stato della coda
     */
    private Logger l;

    /**
     * Oggetto per la gestione del logging del contenuto della coda
     */
    private LoggerContenutoCode lcq;

    /**
     * ID della coda
     */
    private String id;
    /**
     * Costruttore di default
     */

    /**
     * Numero totale degli elementi inseriti in coda
     */
    private int NumeroTotaleElementiInseriti;
    //Operations

    /**
     * Costruttore di default. Associa come indirizzo di comunicazione di default, quelli presenti nella classe statica Indirizzi.
     * @see Commons.Indirizzi
     */
    public TQueueManager() throws XMLStreamException, IOException{
        tQueue = new ArrayList<TaskDescriptor>();
        portaDelWorker=Indirizzi.portaRicezioneTDTQUeueManager;//15000
        tQueue=new ArrayList<TaskDescriptor>();
        this.id=this.getClass().getSimpleName()+this.hashCode();
        this.l=new Logger("log"+id+".xml",this.getClass().getSimpleName());
        this.lcq=new LoggerContenutoCode("logContenutoCode"+id+".xml");
        this.NumeroTotaleElementiInseriti=0;
    }

    /**Restituisce l'Address.
     *
     * @return Address
     */
    public Address getAddr(){
        return addr;
    }

    /**Setta l'Address.
     *
     * @return Address
     */
    public void setAddr (Address val){
        this.addr = val;
    }

    /**Restituisce l'ArrayList di TaskDescriptor.
     *
     * @return Address
     */
    public ArrayList<TaskDescriptor> getTQueue(){
        return tQueue;
    }


    /**Setta l'ArrayList di TaskDescriptor.
     *
     * @param val lista di TaskDescriptor
     */
    public void setTQueue(ArrayList<TaskDescriptor> val){
        this.tQueue = val;
    }

    //Operations Redefined Fron TQueue

    /**Aggiunge un TaskDescriptor alla lista tQueue.
     *
     * @param ts TaskDescriptor
     * @return dimensione lista
     */
    public  int enqueue(TaskDescriptor ts){
       synchronized(tQueue){
        this.tQueue.add(ts);
        l.merge(ts.getVectorClock());
        this.NumeroTotaleElementiInseriti++;
            try {
                l.logging(new LogStatoCoda(this.getClass().getSimpleName(), id, "Aggiunto in coda " + ts.toString(), String.valueOf(System.currentTimeMillis()), this.NumeroTotaleElementiInseriti, this.tQueue.size()));

                lcq.logging(tQueue);
            } catch (InterruptedException ex) {
                java.util.logging.Logger.getLogger(TQueueManager.class.getName()).log(Level.SEVERE, null, ex);
            }
        tQueue.notify();
        return this.tQueue.size();
        }
    

    }

    /**Preleva il primo TaskDescriptor dalla lista tQueue.
     *
     * @return TaskDescriptor
     */
    public synchronized TaskDescriptor dequeue(){
        TaskDescriptor td=this.tQueue.remove(0);
        this.NumeroTotaleElementiInseriti--;
        try {
            l.logging(new LogStatoCoda(this.getClass().getSimpleName(), id, "Rimosso dalla coda " + td.toString(), String.valueOf(System.currentTimeMillis()), this.NumeroTotaleElementiInseriti, this.tQueue.size()));
            lcq.logging(tQueue);
        } catch (InterruptedException ex) {
            java.util.logging.Logger.getLogger(TQueueManager.class.getName()).log(Level.SEVERE, null, ex);
        }
        td.setVectorClock(l.getVectorClock());
        return td;
    }

    /**
     * run() del Thread per la ricezione dei TaskDescriptor dall'Activity (mediante TQManagerProxy).
     */
    public void run() {
        
        System.out.println("TQUEUEMan: lanciato servizio su porta: "+this.portaDelWorker);
        Utility u=new Utility();
       
        u.inizializzaServerRicezioneUDP(this.portaDelWorker);
        
        while(true)
        {
            try
            {

                u2=new Utility();
                //SI BLOCCA ALL'ISTRUZIONE SUCCESSIVA
                TaskDescriptor td = (TaskDescriptor) u.riceviOggettoSerializzatoUDP();// su 15000
                
                Integer size = this.enqueue(td);
                
                System.out.println("%%%%% TQM <--- "+u.getPortaMittente()+" "+u.getMittente());
                //u2.chiudiSocket();//non era chiusa
                 System.out.println("%%%%% TQM <--- u2 close");
                u3=new Utility();
                System.out.println("%%%%% TQM ---> "+u.getPortaMittente()+" "+u.getMittente());
                Thread.sleep(200);
                u3.invioOggettoSerializzatoUDP(size, u.getMittente(), Indirizzi.portaRicezioneTD);//15500 //SET PORTA DEL MANAGER
                //16000
                u3.chiudiSocket();
                System.out.println("%%%%% TQM ---> u3 close");
                

            }
            catch (Exception ex) {
               ex.printStackTrace();
               u2.chiudiSocket();
               u3.chiudiSocket();
               System.exit(0);
            }


            
        }


    }

 

}
